<?php

/**
 * 本文件记录和查询用户的统计信息
 *
 * Sample Code
 * <code>
 *     $stat = new UCModUserStatistics($user_id);
 *     echo $stat->getValue(UC_STAT_COMMENTS_TO_CNT);
 *     $stat->increaseValue(UC_STAT_MOOD_CNT);
 * </code>
 * @note	存储的数据必须是整数
 *             在更新数据的时候如果需要更新多个字段，建议采用setValues或者increaseValues函数
 * 
 * @author    徐鹏程 <xupengcheng@snda.com>
 * @version   0.0.1		2010/03/29
 */

require_once(dirname(__FILE__).'/../../libraries/UCLibKVDB.php');
require_once(dirname(__FILE__).'/../../../unified/SDOApiPeopleService.php');

/**
 * 各个统计字段名的定义
 * 其中：
 *   _UC_STAT_STATRT和_UC_STAT_END 用于校验数据，请勿使用
 *   其余都用int表示
 */

define('_UC_STAT_STATRT', 0);
define('UC_STAT_MOOD_CNT', 1);

define('UC_STAT_LAST_LOGIN_TIME', 2); // 最后登陆时间
define('UC_STAT_LAST_LOGIN_IP_0', 3); // 最后登陆IP 0
define('UC_STAT_LAST_LOGIN_IP_1', 4); // 最后登陆IP 1
define('UC_STAT_LAST_LOGIN_IP_2', 5); // 最后登陆IP 2
define('UC_STAT_LOGIN_TIMES', 6); // 登陆次数
define('UC_STAT_LOGIN_DAYS', 7); // 登陆天数
define('UC_STAT_CONTINUOUS_LOGIN_DAYS', 8); // 连续登陆天数
define('UC_STAT_MODAL_CNT', 9); // 徽章个数
define('UC_STAT_VISITED_FRIENDS_PAGE', 10); // 是否第一次进入好友页面
define('UC_STAT_NICKNAME_UPDATE_TIME', 11); // 昵称的上次修改时间
define('UC_STAT_HIT_7_DAYS', 12); // 已经连续登陆过7天鸟
define('UC_STAT_MOOD_RETWITTER_CNT', 13);
define('UC_STAT_MOOD_MEDAL_CNT', 14); // 勋章规则中的推他计数
define('_UC_STAT_END', 15);

/**
 * UCModUserStatistics类用于查询/更新用户统计信息
 * 在更新数据的时候如果需要更新多个字段，建议采用setValues或者increaseValues函数
 * Sample:
 *     ... ... ... ...
 *     $stat = UCModUserStatistics::getStat($user_id);
 *     echo $stat->getValue(UC_STAT_COMMENTS_TO_CNT);
 *     $stat->increaseValue(UC_STAT_MOOD_CNT);
 *     ... ... ... ...
 */
class UCModUserStatistics {
	private $_user_id;
	private $_user_statistics = null;

	private $_db;
	private $_errorNo = 0;

	private static $_cached_stats = array();

	/**
	 * 获取UCModUserStatistics实例
	 * @param user_id: 用户id
	 * @return: UCModUserStatistics实例
	 */
	public static function getStat($user_id) {
		if (isset(self::$_cached_stats[$user_id])) return self::$_cached_stats[$user_id];
		
		$stat = new UCModUserStatistics($user_id);
		self::$_cached_stats[$user_id] = $stat;
		return $stat;
	}
	
	/**
	 * 构造函数
	 * @param user_id: 用户id
	 */
	public function __construct($user_id) {
		$this->_user_id = $user_id;
		$this->_user_statistics = array();
		$this->_db = new UCLibKVDB(UCLibKVDB::$CHANNEL_STATISTICS);

		// fix old data
		$values = $this->_db->get($user_id);
		if ($values !== false) {
			$values = unserialize($values);
			foreach ($values as $k => $v) {
				$this->_db->put($user_id.".".$k, $v);
			}
			$this->_db->delete($user_id);
		}
	}

	/**
	 * 获取错误信息
	 * @return 错误信息
	 */
	 public function getLastErrorNo() {
		 return $this->_errorNo;
	 }

	/**
	 * 获取统计信息的值
	 * @param type: 字段类型
	 */
	public function getValue($type) {
		if (!$this->_checkType($type)) return false;

		if ($this->_read($type) === false) return false;
		
		if (isset($this->_user_statistics[$type])) return $this->_user_statistics[$type];
		return 0;  // 统计数据默认返回0
	}

	/**
	 * 批量获取统计信息的值
	 * @param types: 字段类型数组
	 */
	public function getValues($types) {
		if ($this->_read($types) === false) return false;

		$result = array();
		foreach ($types as $type) {
			if (!$this->_checkType($type)) return false;
			$value = 0;  // 统计数据默认返回0
			if (isset($this->_user_statistics[$type])) $value = $this->_user_statistics[$type];
			$result[$type] = $value;
		}
		return $result;
	}

	/**
	 * 增加统计信息的值
	 * @param type: 字段类型
	 * @param amount: 增量(可以为负)
	 */
	public function increaseValue($type, $amount = 1) {
		if (!$this->_checkType($type)) return false;

		if (isset($this->_user_statistics[$type])) $this->_user_statistics[$type] += $amount;

		// 写入数据库
		SDOApiPeopleService::updateCountStatistic($this->_user_id, array("title" => $type, "titleCount" => $amount));

		// 写入TT
		if ($this->_db->increment($this->_user_id.".".$type, $amount)) {
			return true;
		} else {
			$this->_errorNo = 2;
			return false;
		}
	}

	/**
	 * 设置统计信息的值
	 * @param type: 字段类型
	 * @param value: 字段的值
	 */
	public function setValue($type, $value) {
		if (!$this->_checkType($type)) return false;
		$this->_user_statistics[$type] = $value;
		
		// 写入数据库
		SDOApiPeopleService::updateStatistic($this->_user_id, array("title" => $type, "titleCount" => $value));

		// 写入TT
		if ($this->_db->put($this->_user_id.".".$type, $value)) {
			return true;
		} else {
			$this->_errorNo = 2;
			return false;
		}
	}

	/**
	 * 记录用户登陆时候的统计，当用户登陆的时候，需要
	 *   1，追加IP
	 *   2，修改最后登陆时间
	 * @param ip: 需要增加的登陆IP
	 */
	public function onUserLogin($ip) {
		if ($this->_read(array(
				UC_STAT_LAST_LOGIN_IP_0,
				UC_STAT_LAST_LOGIN_IP_1,
				UC_STAT_LAST_LOGIN_IP_2,
				UC_STAT_LOGIN_TIMES,
				UC_STAT_LOGIN_DAYS,
				UC_STAT_LAST_LOGIN_TIME,
				UC_STAT_CONTINUOUS_LOGIN_DAYS,
			)) === false) return false;
		$ks = array();

		if (isset($this->_user_statistics[UC_STAT_LAST_LOGIN_IP_2])) {
			$this->_user_statistics[UC_STAT_LAST_LOGIN_IP_0] = $this->_user_statistics[UC_STAT_LAST_LOGIN_IP_1];
			$this->_user_statistics[UC_STAT_LAST_LOGIN_IP_1] = $this->_user_statistics[UC_STAT_LAST_LOGIN_IP_2];
			$this->_user_statistics[UC_STAT_LAST_LOGIN_IP_2] = self::_ip2long($ip);

			$ks []= UC_STAT_LAST_LOGIN_IP_0;
			$ks []= UC_STAT_LAST_LOGIN_IP_1;
			$ks []= UC_STAT_LAST_LOGIN_IP_2;
		} else  if (isset($this->_user_statistics[UC_STAT_LAST_LOGIN_IP_1])) {
			$this->_user_statistics[UC_STAT_LAST_LOGIN_IP_2] = self::_ip2long($ip);
			$ks []= UC_STAT_LAST_LOGIN_IP_2;
		} else  if (isset($this->_user_statistics[UC_STAT_LAST_LOGIN_IP_0])) {
			$this->_user_statistics[UC_STAT_LAST_LOGIN_IP_1] = self::_ip2long($ip);
			$ks []= UC_STAT_LAST_LOGIN_IP_1;
		} else {
			$this->_user_statistics[UC_STAT_LAST_LOGIN_IP_0] = self::_ip2long($ip);
			$ks []= UC_STAT_LAST_LOGIN_IP_0;
		}

		if (isset($this->_user_statistics[UC_STAT_LOGIN_TIMES])) {
			$this->_user_statistics[UC_STAT_LOGIN_TIMES] = $this->_user_statistics[UC_STAT_LOGIN_TIMES] + 1;
		} else {
			$this->_user_statistics[UC_STAT_LOGIN_TIMES] = 1;
		}
		$ks []= UC_STAT_LOGIN_TIMES;

		if (!isset($this->_user_statistics[UC_STAT_LOGIN_DAYS])) {
			$this->_user_statistics[UC_STAT_LOGIN_DAYS] = 0;
			$ks []= UC_STAT_LOGIN_DAYS;
		}
		
		$now = time();

		if (isset($this->_user_statistics[UC_STAT_LAST_LOGIN_TIME])) {
			$last = $this->_user_statistics[UC_STAT_LAST_LOGIN_TIME];
			$now_str = date("Y-m-d", $now);
			$last_str = date("Y-m-d", $last);
			if ($now_str == $last_str) { // do nothing
			} else {
				$this->_user_statistics[UC_STAT_LOGIN_DAYS] += 1;
				$ks []= UC_STAT_LOGIN_DAYS;
				$this->_user_statistics[UC_STAT_LAST_LOGIN_TIME] = $this->_user_statistics[UC_STAT_LAST_LOGIN_TIME] + 1;
				$ks []= UC_STAT_LAST_LOGIN_TIME;
				$yesterday = date("Y-m-d", $now - 24 * 3600);
				if ($yesterday == $last_str) {
					if (isset($this->_user_statistics[UC_STAT_CONTINUOUS_LOGIN_DAYS])) {
						$this->_user_statistics[UC_STAT_CONTINUOUS_LOGIN_DAYS] += 1;
						if ($this->_user_statistics[UC_STAT_CONTINUOUS_LOGIN_DAYS] >= 7 && !isset($this->_user_statistics[UC_STAT_HIT_7_DAYS])) {
							$this->_user_statistics[UC_STAT_HIT_7_DAYS] = 1;
							$ks []= UC_STAT_HIT_7_DAYS;
						}
						$ks []= UC_STAT_CONTINUOUS_LOGIN_DAYS;
					} else {
						$this->_user_statistics[UC_STAT_CONTINUOUS_LOGIN_DAYS] = 1;
						$ks []= UC_STAT_CONTINUOUS_LOGIN_DAYS;
					}
				} else {
					$this->_user_statistics[UC_STAT_CONTINUOUS_LOGIN_DAYS] = 0;
					$ks []= UC_STAT_CONTINUOUS_LOGIN_DAYS;
				}
			}
		} else {
			$this->_user_statistics[UC_STAT_CONTINUOUS_LOGIN_DAYS] = 1;
			$ks []= UC_STAT_CONTINUOUS_LOGIN_DAYS;
			$this->_user_statistics[UC_STAT_LOGIN_DAYS] += 1;
			$ks []= UC_STAT_LOGIN_DAYS;
		}

		if (!isset($this->_user_statistics[UC_STAT_CONTINUOUS_LOGIN_DAYS]) || $this->_user_statistics[UC_STAT_CONTINUOUS_LOGIN_DAYS] <= 0) $this->_user_statistics[UC_STAT_CONTINUOUS_LOGIN_DAYS] = 1;

		$this->_user_statistics[UC_STAT_LAST_LOGIN_TIME] = $now;
		$ks []= UC_STAT_LAST_LOGIN_TIME;

		$values = array();
		foreach ($ks as $k) {
			$values[$k] = $this->_user_statistics[$k];
		}

		return $this->setValues($values);
	}

	/**
	 * 批量增加统计信息的值
	 * @param values: 需要增加的 键=>值 对，比如
	 *     array(UC_STAT_COMMENTS_TO_NEW_CNT => 1,
	 *              UC_STAT_COMMENTS_TO_REPLY_NEW_CNT => -1)
	 */
	public function increaseValues($values) {
		$ks = array();
		$vs = array();
		foreach($values as $type => $value) {
			if (!$this->_checkType($type)) return false;
			$ks []= $type;
			$vs []= $value;
		}

		// 写入数据库
		SDOApiPeopleService::updateCountStatistic($this->_user_id, array("title" => join(",", $ks), "titleCount" =>  join(",", $vs)));

		// 写入TT
		$ret = true;
		foreach($values as $type => $amount) {
			if ($this->_db->increment($this->_user_id.".".$type, $amount) === false) {
				$this->_errorNo = 2;
				$ret = false;
			}
		}
		return $ret;
	}

	/**
	 * 批量设置统计信息的值
	 * @param user_id: 用户id
	 * @param values: 需要设置的 键=>值 对，比如
	 *     array(UC_STAT_COMMENTS_TO_NEW_CNT => 12,
	 *              UC_STAT_COMMENTS_TO_REPLY_NEW_CNT => 0)
	 */
	public function setValues($values) {
		$ks = array();
		$vs = array();
		foreach($values as $type => $value) {
			if (!$this->_checkType($type)) return false;
			$ks []= $type;
			$vs []= $value;
		}

		// 写入数据库
		SDOApiPeopleService::updateStatistic($this->_user_id, array("title" => join(",", $ks), "titleCount" =>  join(",", $vs)));

		// 写入TT
		$ret = true;
		foreach($values as $type => $value) {
			if ($this->_db->put($this->_user_id.".".$type, $value) === false) {
				$this->_errorNo = 2;
				$ret = false;
			}
		}
		return $ret;
	}


	/**
	 * 读取信息
	 */
	private function _read($type) {
		if (is_array($type)) {
			$keys = array();
			$skeys = array();
			foreach ($type as $t) {
				if (isset($this->_user_statistics[$t])) continue;
				$keys []= $this->_user_id.".".$t;
				$skeys[] = $t;
			}

			$values = $this->_db->get($keys);
			if ($values === false) return false;

			foreach($skeys as $i => $t) $this->_user_statistics[$t] = $values[$i];
		} else {
			if (isset($this->_user_statistics[$type])) return;

			$value = $this->_db->get($this->_user_id.".".$type);

			if (!$value) $value = 0;

			$this->_user_statistics[$type] = $value;
		}
		return true;
	}


	/**
	 * 检查字段名是否合法
	 * @param type: 字段类型
	 */
	private function _checkType($type) {
		if (gettype($type) == "integer" && $type >= _UC_STAT_STATRT && $type <= _UC_STAT_END) {
			return true;
		} else {
			$this->_errorNo = 1;
			return false;
		}
	}

	public static function _ip2long($ip) {
		$long= ip2long($ip);
		if ($long > 2147483647) {
			$long -= 4294967296;
		}
		return $long;
	}

	public static function _long2ip($long) {
		$long = intval($long);
		if ($long < 0) {
			$long += 4294967296;
		}
		return long2ip($long);
	}
}
/*
$stat = UCModUserStatistics::getStat(8061248);
var_dump($stat->getValues(array(UC_STAT_MOOD_CNT)));
var_dump($stat->getLastErrorNo());
*/